package com.jack.collections;

import java.util.concurrent.*;
import java.util.*;

class Writer2 implements Runnable {
    private Map<String, Integer> map;
    private static int index;
    private int nIteration; 
    private Random random = new Random();
    char[] chars = "abcdefghijklmnopqrstuvwxyz".toCharArray();
    private final CountDownLatch latch;

    public Writer2(Map<String, Integer> map, int nIteration, CountDownLatch latch) {
        this.map = map;
        this.nIteration = nIteration;
        this.latch = latch;
    }

    private synchronized String getNextString() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 5; i++) {
            char c = chars[random.nextInt(chars.length)];
            sb.append(c);
        }
        sb.append(index);
        if(map.containsKey(sb.toString()))
            System.out.println("dublicate:" + sb.toString());
        return sb.toString();
    }

    private synchronized int getNextInt() { return index++; }

    @Override
    public void run() {
        while(nIteration-- > 0) {
            map.put(getNextString(), getNextInt());
        }
        latch.countDown();
    }
}

public class FourtyTwo {
    static final int nIteration = 100000;
    static final int nThreads = 8;
    static Long testMap(Map<String, Integer> map) throws InterruptedException{
        String name = map.getClass().getSimpleName(); 
        CountDownLatch latch = new CountDownLatch(nThreads);
        long startTime = System.currentTimeMillis();
            ExecutorService exec = Executors.newFixedThreadPool(nThreads);
            for(int i = 0; i < nThreads; i++)
                exec.submit(new Writer2(map, nIteration, latch));
            latch.await();  
            exec.shutdown();
        long endTime = System.currentTimeMillis();
        System.out.format(name + ": that took %,d milliseconds %n", (endTime - startTime));
        return (endTime - startTime);
    }
    public static void main(String[] args) throws InterruptedException {
        ArrayList<Long> result = new ArrayList<Long>() {
            @Override
            public String toString() {
                Long result = 0L;
                Long size = new Long(this.size());
                for(Long i : this)
                    result += i;
                return String.valueOf(result/size);
            }
        }; 

        Map<String, Integer> map1 = Collections.synchronizedMap(new HashMap<String, Integer>());
        Map<String, Integer> map2 = new ConcurrentHashMap<>();

        System.out.println("Rinning test...");
        for(int i = 0; i < 5; i++) {
            result.add(testMap(map1));
            result.add(testMap(map2));
        }
        System.out.println("Average time:" + result + " milliseconds");

    }

}